package com.zhang.autotouch.service;

import android.accessibilityservice.AccessibilityService;
import android.accessibilityservice.GestureDescription;
import android.annotation.SuppressLint;
import android.graphics.Path;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.WindowManager;
import android.view.accessibility.AccessibilityEvent;
import android.widget.TextView;

import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;

import androidx.annotation.RequiresApi;

import com.zhang.autotouch.R;
import com.zhang.autotouch.TouchEventManager;
import com.zhang.autotouch.bean.AppInfo;
import com.zhang.autotouch.bean.AutoEvent;
import com.zhang.autotouch.bean.AutoItem;
import com.zhang.autotouch.bean.AutoItemMessage;
import com.zhang.autotouch.bean.AutoItemTypeEnum;
import com.zhang.autotouch.bean.GameManage;
import com.zhang.autotouch.bean.SearchPoint;
import com.zhang.autotouch.bean.TouchEvent;
import com.zhang.autotouch.bean.TouchPoint;
import com.zhang.autotouch.bean.mhxy.MhxyBaotu;
import com.zhang.autotouch.bean.mhxy.MhxyBase;
import com.zhang.autotouch.bean.mhxy.MhxyLoopState;
import com.zhang.autotouch.bean.mhxy.MhxyShimen;
import com.zhang.autotouch.utils.DensityUtil;
import com.zhang.autotouch.utils.WindowUtils;

import java.text.DecimalFormat;
import java.util.List;

import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.core.Observer;
import io.reactivex.rxjava3.disposables.Disposable;
import io.reactivex.rxjava3.functions.Consumer;
import io.reactivex.rxjava3.plugins.RxJavaPlugins;
import io.reactivex.rxjava3.schedulers.Schedulers;

/**
 * 无障碍服务-自动点击
 * @date 2019/9/6 16:23
 */
@RequiresApi(api = Build.VERSION_CODES.N)
public class AutoTouchService extends AccessibilityService {

    private final String TAG = "AutoTouchService";
    //自动点击事件
    private TouchPoint autoTouchPoint;
    // 自动脚本内容
    private List<AutoItem> autoItems;
    Disposable disposable;
    @SuppressLint("HandlerLeak")
    private Handler handler = new Handler(Looper.getMainLooper());
    private WindowManager windowManager;
    private TextView tvTouchPoint;
    //倒计时
    private float countDownTime;
    private DecimalFormat floatDf = new DecimalFormat("#0.0");
    //修改点击文本的倒计时
    private Runnable touchViewRunnable;

    @Override
    protected void onServiceConnected() {
        super.onServiceConnected();
        handler = new Handler();
        EventBus.getDefault().register(this);
        windowManager = WindowUtils.getWindowManager(this);

        RxJavaPlugins.setErrorHandler(new Consumer<Throwable>() {
            @Override
            public void accept(Throwable throwable) throws Throwable {
                Log.e(TAG, throwable.toString());
            }
        });
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onReciverTouchEvent(AutoEvent event) {
        Log.d(TAG, "onReciverAutoEvent: " + event.toString());
        AppInfo.getInstance().setAutoAction(event.getAction());
        //handler.removeCallbacks(autoTouchRunnable);
        switch (event.getAction()) {
            case AutoEvent.ACTION_START:
                autoItems = event.getAutoItems();
                onAutoItemClick();
                //onAutoClick();
                break;
            case AutoEvent.ACTION_END:
                //handler.removeCallbacks(autoTouchRunnable);
                //handler.removeCallbacks(touchViewRunnable);
                stopAutoItem();
                removeTouchView();
                //autoTouchPoint = null;
                break;
            case AutoEvent.ACTION_CONTINUE:
                if (autoTouchPoint != null) {
                    onAutoClick();
                }
                break;
            case AutoEvent.ACTION_PAUSE:
                handler.removeCallbacks(autoTouchRunnable);
                handler.removeCallbacks(touchViewRunnable);
                break;
            case AutoEvent.ACTION_STOP:
                handler.removeCallbacks(autoTouchRunnable);
                handler.removeCallbacks(touchViewRunnable);
                removeTouchView();
                autoTouchPoint = null;
                break;
        }
    }

    @Subscribe(threadMode = ThreadMode.MAIN)
    public void onReciverTouchEvent(TouchEvent event) {
        Log.d(TAG, "onReciverTouchEvent: " + event.toString());
        TouchEventManager.getInstance().setTouchAction(event.getAction());
        handler.removeCallbacks(autoTouchRunnable);
        switch (event.getAction()) {
            case TouchEvent.ACTION_START:
                autoTouchPoint = event.getTouchPoint();
                onAutoClick();
                break;
            case TouchEvent.ACTION_CONTINUE:
                if (autoTouchPoint != null) {
                    onAutoClick();
                }
                break;
            case TouchEvent.ACTION_PAUSE:
                handler.removeCallbacks(autoTouchRunnable);
                handler.removeCallbacks(touchViewRunnable);
                break;
            case TouchEvent.ACTION_STOP:
                handler.removeCallbacks(autoTouchRunnable);
                handler.removeCallbacks(touchViewRunnable);
                removeTouchView();
                autoTouchPoint = null;
                break;
        }
    }

    /**
     * 执行自动点击
     */
    private void onAutoClick() {
        if (autoTouchPoint != null) {
            handler.postDelayed(autoTouchRunnable, getDelayTime());
            showTouchView();
        }
    }

    /**
     * 停止自动任务
     */
    private void stopAutoItem(){
        if(disposable != null && !disposable.isDisposed()){
            disposable.dispose();
        }
    }

    // 任务相关

    // End 任务相关

    /**
     * 模拟滑动事件
     *
     * @param fx1
     * @param fy1
     * @param fx2
     * @param fy2
     * @param startTime 0即可执行
     * @param duration  滑动时长
     * @return 执行是否成功
     */
    private void swipe(float fx1, float fy1,float fx2 , float fy2 ,final int startTime , final int duration) {
        Log.e("Tag","模拟滑动事件");
        int x1 = (int)fx1;
        int y1 = (int)fy1;
        int x2 = (int)fx2;
        int y2 = (int)fy2;
        GestureDescription.Builder builder = new GestureDescription.Builder();
        Path p = new Path();
        p.moveTo(x1 , y1);
        p.lineTo(x2 , y2);
        builder.addStroke(new GestureDescription.StrokeDescription(p, 0L, duration));
        GestureDescription gesture = builder.build();
        dispatchGesture(gesture, new GestureResultCallback() {
            @Override
            public void onCompleted(GestureDescription gestureDescription) {
                super.onCompleted(gestureDescription);
                Log.e("Tag", "onCompleted: 完成..........");
            }

            @Override
            public void onCancelled(GestureDescription gestureDescription) {
                super.onCancelled(gestureDescription);
                Log.e("Tag", "onCompleted: 取消..........");
            }
        }, null);

    }

    /**
     * 模拟点击事件
     *
     * @param fx
     * @param fy
     */
    private void tap(float fx, float fy, final int startTime , final int duration) {
        Log.e("Tag","模拟点击事件");
        int x = (int)fx;
        int y = (int)fy;
        GestureDescription.Builder builder = new GestureDescription.Builder();
        Path p = new Path();
        p.moveTo(x , y);
        builder.addStroke(new GestureDescription.StrokeDescription(p, startTime, duration));
        GestureDescription gesture = builder.build();
        dispatchGesture(gesture, new GestureResultCallback() {
            @Override
            public void onCompleted(GestureDescription gestureDescription) {
                super.onCompleted(gestureDescription);
                Log.e("Tag", "onCompleted: 完成..........");
            }

            @Override
            public void onCancelled(GestureDescription gestureDescription) {
                super.onCancelled(gestureDescription);
                Log.e("Tag", "onCompleted: 取消..........");
            }
        }, null);

    }

    private void onAutoItemClick() {
        if(autoItems != null){
            // 执行串行任务，从第一个任务开始执行，通过RXJAVA实现
            stopAutoItem();
            Observable.create(new ObservableOnSubscribe<AutoItemMessage>() {
                @Override
                public void subscribe(@NonNull ObservableEmitter<AutoItemMessage> emitter) throws Throwable {
                    AutoItemMessage autoItemMessage = new AutoItemMessage(emitter);
                    for (AutoItem ai:
                         autoItems) {
                        if(!ai.isEnable())
                            continue;
                        autoItemMessage.setAutoItem(ai);
                        switch (ai.getType()){
                            case BAOTU:
                                autoItemMessage.showMessage("开始");
                                MhxyBase mhxyBaotu = new MhxyBaotu(GameManage.getInstance(), autoItemMessage);
                                mhxyBaotu.loop();
                                break;
                            case SHIMEN:
                                autoItemMessage.showMessage("开始");
                                MhxyBase mhxyShimen = new MhxyShimen(GameManage.getInstance(), autoItemMessage);
                                mhxyShimen.loop();
                                break;
                            case ZHUOGUI:
                                autoItemMessage.showMessage("开始");
                                for(int i = 0;i<10;i++){
                                    SearchPoint sp = GameManage.getInstance().searchText("笔记");
                                    if(sp != null){
                                        autoItemMessage.showMessage("发现活动坐标 "+sp.toString());
                                        autoItemMessage.clickMessage(sp.getClickX(), sp.getClickY(), "点击活动坐标");
                                        break;
                                    }else{
                                        autoItemMessage.showMessage("未发现活动坐标 倒计时 "+(10-i));
                                    }
                                    Thread.sleep(10000);
                                }
                                break;
                            default:{
                                break;
                            }
                        }
                    }

                    Thread.sleep(3000);
                    emitter.onComplete();
                }
            }).subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(new Observer<AutoItemMessage>() {
               @Override
               public void onSubscribe(@NonNull Disposable d) {
                    disposable = d;
               }

               @Override
               public void onNext(@NonNull AutoItemMessage s) {
                   switch (s.getType()){
                       case SHOW:
                           showLog(s.getContent());
                           break;
                       case SWIPE:
                           showLog(s.getContent());
                           swipe(s.getX(), s.getY(), s.getX1(), s.getY1(), s.getStartTime(), s.getDuration());
                           break;
                       case CLICK:
                           showLog(s.getContent());
                           tap(s.getX(), s.getY(), s.getStartTime(), s.getDuration());
//                           Path path = new Path();
//                           path.moveTo(s.getX(), s.getY());
//                           GestureDescription.Builder builder = new GestureDescription.Builder();
//                           GestureDescription gestureDescription = builder.addStroke(
//                                   new GestureDescription.StrokeDescription(path, 0, 100))
//                                   .build();
//                           dispatchGesture(gestureDescription, new AccessibilityService.GestureResultCallback() {
//                               @Override
//                               public void onCompleted(GestureDescription gestureDescription) {
//                                   super.onCompleted(gestureDescription);
//                                   Log.d(TAG, "滑动结束" + gestureDescription.getStrokeCount());
//                               }
//
//                               @Override
//                               public void onCancelled(GestureDescription gestureDescription) {
//                                   super.onCancelled(gestureDescription);
//                                   Log.d(TAG, "滑动取消");
//                               }
//                           }, null);
                           break;
                   }
               }

               @Override
               public void onError(@NonNull Throwable e) {

               }

               @Override
               public void onComplete() {
                   showLog("所有任务完成，共计："+autoItems.size());
               }
            });
        }

        showLog("未发现任务，请停止并重新开始");
    }

    private Runnable autoTouchRunnable = new Runnable() {
        @Override
        public void run() {
            Log.d(TAG, "onAutoClick: " + "x=" + autoTouchPoint.getX() + " y=" + autoTouchPoint.getY());
            Path path = new Path();
            path.moveTo(autoTouchPoint.getX(), autoTouchPoint.getY());
            GestureDescription.Builder builder = new GestureDescription.Builder();
            GestureDescription gestureDescription = builder.addStroke(
                    new GestureDescription.StrokeDescription(path, 0, 100))
                    .build();
            dispatchGesture(gestureDescription, new AccessibilityService.GestureResultCallback() {
                @Override
                public void onCompleted(GestureDescription gestureDescription) {
                    super.onCompleted(gestureDescription);
                    Log.d("AutoTouchService", "滑动结束" + gestureDescription.getStrokeCount());
                }

                @Override
                public void onCancelled(GestureDescription gestureDescription) {
                    super.onCancelled(gestureDescription);
                    Log.d("AutoTouchService", "滑动取消");
                }
            }, null);
            onAutoClick();
        }
    };

    private long getDelayTime() {
//        int random = (int) (Math.random() * (30 - 1) + 1);
//        return autoTouchEvent.getDelay() * 1000L + random;
        return autoTouchPoint.getDelay() * 1000L;
    }

    @Override
    public void onAccessibilityEvent(AccessibilityEvent event) { }

    @Override
    public void onInterrupt() { }

    @Override
    public void onDestroy() {
        super.onDestroy();

        stopAutoItem();

        handler.removeCallbacksAndMessages(null);
        removeTouchView();
    }

    /**
     * 显示提示信息
     */
    private void showLog(String content) {
        Log.i(TAG, content);
        if (autoItems != null) {
            //创建触摸点View
            if (tvTouchPoint == null) {
                tvTouchPoint = (TextView) LayoutInflater.from(this).inflate(R.layout.window_touch_point, null);
                tvTouchPoint.setPadding(16, 0, 16, 0);
                int width = WindowManager.LayoutParams.WRAP_CONTENT;
                int height = DensityUtil.dip2px(this, 40);
                WindowManager.LayoutParams params = WindowUtils.newWmParams(width, height);
                params.gravity = Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL;
                params.x = 0;
                params.y = 0;
                params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                windowManager.addView(tvTouchPoint, params);
            }
            tvTouchPoint.setText(content);
        }
    }

    /**
     * 显示界面显示内容
     */
    private void showTouchView(String content) {
        if (autoItems != null) {
            //创建触摸点View
            if (tvTouchPoint == null) {
                tvTouchPoint = (TextView) LayoutInflater.from(this).inflate(R.layout.window_touch_point, null);
            }
            //显示触摸点View
            if (windowManager != null && !tvTouchPoint.isAttachedToWindow()) {
                //int width = DensityUtil.dip2px(this, 40);
                int width = WindowManager.LayoutParams.WRAP_CONTENT;
                int height = DensityUtil.dip2px(this, 40);
                WindowManager.LayoutParams params = WindowUtils.newWmParams(width, height);
                params.gravity = Gravity.START | Gravity.TOP;
                params.x = autoTouchPoint.getX() - width/2;
                params.y = autoTouchPoint.getY() - width;
                params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                windowManager.addView(tvTouchPoint, params);
            }
            if(touchViewRunnable == null) {
                touchViewRunnable = new Runnable() {
                    @Override
                    public void run() {
                        tvTouchPoint.setText(content);
                    }
                };
            }
            handler.post(touchViewRunnable);
        }
    }

    /**
     * 显示倒计时
     */
    private void showTouchView() {
        if (autoTouchPoint != null) {
            //创建触摸点View
            if (tvTouchPoint == null) {
                tvTouchPoint = (TextView) LayoutInflater.from(this).inflate(R.layout.window_touch_point, null);
            }
            //显示触摸点View
            if (windowManager != null && !tvTouchPoint.isAttachedToWindow()) {
                //int width = DensityUtil.dip2px(this, 40);
                int width = WindowManager.LayoutParams.WRAP_CONTENT;
                int height = DensityUtil.dip2px(this, 40);
                WindowManager.LayoutParams params = WindowUtils.newWmParams(width, height);
                params.gravity = Gravity.START | Gravity.TOP;
                params.x = autoTouchPoint.getX() - width/2;
                params.y = autoTouchPoint.getY() - width;
                params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
                windowManager.addView(tvTouchPoint, params);
            }
            //开启倒计时
            countDownTime = autoTouchPoint.getDelay();
            if(touchViewRunnable == null) {
                touchViewRunnable = new Runnable() {
                    @Override
                    public void run() {
                        handler.removeCallbacks(touchViewRunnable);
                        Log.d("触摸倒计时", countDownTime + "");
                        if (countDownTime > 0) {
                            float offset = 0.1f;
                            tvTouchPoint.setText(floatDf.format(countDownTime));
                            countDownTime -= offset;
                            handler.postDelayed(touchViewRunnable, (long) (1000L * offset));
                        } else {
                            removeTouchView();
                        }
                    }
                };
            }
            handler.post(touchViewRunnable);
        }
    }

    private void removeTouchView() {
        if (windowManager != null && tvTouchPoint != null) {
            windowManager.removeView(tvTouchPoint);
            tvTouchPoint = null;
        }
    }
}
